home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / Pascal / Applications / P4⁄Mac 2.0d4 / Mac source 2.0 / Console.p < prev    next >
Encoding:
Text File  |  1996-09-28  |  10.4 KB  |  473 lines  |  [TEXT/PJMM]

  1. {A TTY-style console window for P4/Mac, by Ingemar Ragnemalm 1996}
  2.  
  3. {This unit implements basic text-based I/O in a window. It shows white text on a blue bottom, in order to}
  4. {emphasize the feeling of "good old 70's", so nobody gets the false impression that this is supposed to}
  5. {be a modern system.}
  6.  
  7. unit Console;
  8.  
  9. interface
  10.     uses
  11.         TransSkel;
  12.  
  13.     type
  14.         CharPointer = ^Char;
  15.     procedure ConsoleWrite (msg: Str255);
  16.     procedure ConsoleWriteLn (msg: Str255);
  17.     procedure ConsoleNewLine;
  18.     function ConsoleReadLn: Str255;
  19.     procedure ConsoleGotoXY (x, y: Integer);
  20.     procedure ConsoleClearScreen;
  21.  
  22.     function ConsoleReadChar: Char;
  23.     function ConsolePeekChar: Char;
  24.     function ConsoleReadInt: Integer;
  25.     function ConsoleReadReal: Real;
  26.     function ConsoleReadEOL: Boolean;
  27.     function ConsoleReadEOF: Boolean;
  28.     function ConsoleInput: CharPointer;
  29.     procedure ConsoleGet;
  30.     procedure ConsoleResetRead;
  31.  
  32.     var
  33.         aborted: Boolean;
  34.  
  35. implementation
  36.  
  37.     type
  38.         Str80 = string[80];
  39.  
  40.     var
  41.         buffer: array[0..23] of Str80;
  42.         posX, posY: Integer;
  43.         gConsoleWindow: WindowPtr;
  44.  
  45.         info: FontInfo;
  46.  
  47.     const
  48.         kConsoleWindowId = 1000;
  49.  
  50.     const
  51.         kLeftArrow = $1C;
  52.         kRightArrow = $1D;
  53.         kUpArrow = $1E;
  54.         kDownArrow = $1F;
  55.  
  56.     procedure SetTextFont (fontName: Str255);
  57.         var
  58.             fontNum: Integer;
  59.     begin
  60.         GetFNum(fontName, fontNum);
  61.         TextFont(fontNum);
  62.     end; {SetTextFont}
  63.  
  64.     procedure Update (resized: Boolean);
  65.         var
  66.             i: Integer;
  67.     begin
  68.         SetPort(gConsoleWindow);
  69.         EraseRect(gConsoleWindow^.portRect);
  70.         for i := 0 to 23 do
  71.             begin
  72.                 MoveTo(info.widMax, i * (info.ascent + info.descent + info.leading) + info.ascent);
  73.                 DrawString(buffer[i]);
  74.             end;
  75.     end; {Update}
  76.  
  77.     procedure ConsoleInit;
  78.     begin
  79.         if gConsoleWindow = nil then
  80.             begin
  81.                 gConsoleWindow := GetNewWindow(kConsoleWindowId, nil, WindowPtr(-1));
  82.                 if gConsoleWindow = nil then
  83.                     begin
  84.                         SysBeep(1);        {Hellre FakeAlert!}
  85.                         ExitToShell;
  86.                     end;
  87.  
  88.                 SetPort(gConsoleWindow);
  89.  
  90.                 if info.ascent = 0 then
  91.                     begin
  92.                         TextSize(9);
  93.                         SetTextFont('Monaco');
  94.                         GetFontInfo(info);
  95.                     end;
  96.  
  97.                 ForeColor(whiteColor);
  98.                 BackColor(blueColor);
  99.  
  100.                 ConsoleClearScreen;
  101.  
  102.                 if SkelWindow(gConsoleWindow, nil, nil, @Update, nil, nil, nil, nil, true) then
  103.                     ;
  104.  
  105.             end;
  106.  
  107.         ShowWindow(gConsoleWindow);
  108.         SelectWindow(gConsoleWindow);
  109.         SetPort(gConsoleWindow);
  110.     end; {ConsoleInit}
  111.  
  112.     procedure ConsoleLinefeed;
  113.     begin
  114.         posY := (posY + 1) mod 24;
  115.     end; {ConsoleLinefeed}
  116.  
  117.     procedure ConsoleUp;
  118.     begin
  119.         posY := (posY + 23) mod 24;
  120.     end; {ConsoleUp}
  121.  
  122.     procedure ConsoleBackSpace;
  123.     begin
  124.         posX := (posX + 78) mod 80 + 1;
  125.         if posX = 80 then
  126.             ConsoleUp;
  127.     end; {ConsoleBackSpace}
  128.  
  129.     procedure ConsoleRight;
  130.     begin
  131.         posX := posX mod 80 + 1;
  132.         if posX = 1 then
  133.             ConsoleLinefeed;
  134.     end; {ConsoleRight}
  135.  
  136.     procedure ConsoleWrite (msg: Str255);
  137.         var
  138.             r: Rect;
  139.             i, j: Integer;
  140.     begin
  141.         ConsoleInit;
  142.  
  143.         for i := 1 to Length(msg) do
  144.             begin
  145.                 if Ord(msg[i]) >= 32 then
  146.                     begin
  147.                         SetPort(gConsoleWindow);
  148.  
  149. {Möjligen kunde man snabba upp detta genom att samla ihop ett antal tecken och skriva alla på en gång!}
  150.  
  151.                         buffer[posY][posX] := msg[i];
  152.                         SetRect(r, posX * info.widMax, posY * (info.ascent + info.descent + info.leading), (posX + 1) * info.widMax, (posY + 1) * (info.ascent + info.descent + info.leading));
  153.                         EraseRect(r);
  154.                         MoveTo(posX * info.widMax, posY * (info.ascent + info.descent + info.leading) + info.ascent);
  155.                         DrawChar(buffer[posY][posX]);
  156.  
  157.                         posX := posX + 1;
  158.                         if posX > 80 then
  159.                             ConsoleNewLine;
  160.  
  161.                     end
  162.                 else
  163.                     case Ord(msg[i]) of
  164.                         9: 
  165.                             SysBeep(1);
  166.                         13: 
  167.                             ConsoleNewLine;
  168.                         12: 
  169.                             ConsoleClearScreen;
  170.                         8, kLeftArrow: 
  171.                             ConsoleBackSpace;
  172.                         10, kDownArrow: 
  173.                             ConsoleLinefeed;
  174.                         kUpArrow: 
  175.                             ConsoleUp;
  176.                         kRightArrow: 
  177.                             ConsoleRight;
  178. {27 = ESCAPE, bra för specialare?}
  179.                         otherwise
  180.                     end; {case}
  181.             end;
  182.  
  183.     end; {ConsoleWrite}
  184.  
  185.     procedure ConsoleWriteLn (msg: Str255);
  186.     begin
  187.         ConsoleWrite(msg);
  188.         ConsoleNewLine;
  189.     end; {ConsoleWriteLn}
  190.  
  191.     procedure ConsoleNewLine;
  192.         var
  193.             j: Integer;
  194.             r: Rect;
  195.     begin
  196.         ConsoleInit;
  197.         SetPort(gConsoleWindow);
  198.  
  199.         posX := 1;
  200.         posY := posY + 1;
  201.         if posY > 23 then
  202.             begin
  203.                 for j := 1 to 23 do
  204.                     buffer[j - 1] := buffer[j];
  205.                 buffer[23] := '                                                                                ';
  206.  
  207.                 posY := 23;
  208.                 ScrollRect(gConsoleWindow^.portRect, 0, -info.ascent - info.descent - info.leading, nil);
  209.                 r := gConsoleWindow^.portRect;
  210.                 r.top := r.bottom - info.ascent - info.descent - info.leading;
  211.                 EraseRect(r);
  212.             end;
  213.     end; {ConsoleNewLine}
  214.  
  215. {Hur skall read/readln från console funka egentligen?}
  216.     function ConsoleReadLn: Str255;
  217.         var
  218.             startReadX, startReadY, endRead: Integer;
  219.             done: Boolean;
  220.             theKey: Char;
  221.             theEvent: EventRecord;
  222.             r: Rect;
  223.  
  224.             flashed: Boolean;
  225.             lastFlash: Longint;
  226.         const
  227.             kFlashTime = 15;
  228.  
  229.         procedure FlashCursor;
  230.         begin
  231.             flashed := not flashed;
  232.  
  233.             SetRect(r, posX * info.widMax, posY * (info.ascent + info.descent + info.leading), (posX + 1) * info.widMax, (posY + 1) * (info.ascent + info.descent + info.leading));
  234.             InvertRect(r);
  235.             lastFlash := TickCount;
  236.         end;
  237.         procedure SynchCursor;
  238.         begin
  239.             if flashed then
  240.                 FlashCursor;
  241.         end;
  242.  
  243.     begin
  244.         ConsoleInit;
  245.  
  246. {Blinkvariabler:}
  247.         flashed := false;
  248.         lastFlash := TickCount;
  249.  
  250.         startReadX := posX;
  251.         startReadY := posY;
  252.         endRead := startReadX;        {För att ha ett giltigt värde.}
  253.         done := false;
  254.  
  255. {Två sätt att göra detta:}
  256. {• TextEdit. Ger visst stöd för att fixa copy/paste och sånt.}
  257. {• Eget.}
  258.  
  259.         repeat
  260.             if GetNextEvent(keyDownMask + autoKeyMask + updateMask, theEvent) then
  261.                 case theEvent.what of
  262.                     keyDown, autoKey: 
  263.                         begin
  264.                             theKey := Char(BitAnd(theEvent.message, charCodeMask));
  265.                             if Ord(theKey) = 13 then {Should handle Enter too!}
  266.                                 begin
  267.                                     SynchCursor;
  268.  
  269.                                     done := true;
  270.                                     endRead := posX;
  271.                                     ConsoleNewLine;
  272.                                 end
  273.                             else if (Ord(theKey) = 8) or (Ord(theKey) = $7F) then
  274.                                 begin
  275.                                     if posX > startReadX then
  276.                                         begin
  277.                                             SynchCursor;
  278.  
  279.                                             ConsoleBackSpace;
  280.                                             ConsoleWrite(' ');
  281.                                             ConsoleBackSpace;
  282.                                         end
  283.                                 end
  284.                             else if (BitAnd(theEvent.modifiers, cmdKey) <> 0) and (theKey = '.') then {or (theKey = Char(27))}
  285.                                 aborted := true
  286.                             else if Ord(theKey) >= 32 then
  287.                                 begin
  288.                                     SynchCursor;
  289.                                     if posX < 80 then
  290.                                         ConsoleWrite(theKey)
  291.                                     else
  292.                                         SysBeep(1);
  293.                                 end;
  294.                         end; {keyDown}
  295.                     updateEvt: 
  296.                         begin
  297.                             if WindowPtr(theEvent.message) = gConsoleWindow then
  298.                                 begin
  299.                                     SetPort(gConsoleWindow);
  300.                                     SynchCursor;
  301.                                     BeginUpdate(gConsoleWindow);
  302.                                     Update(false);
  303.                                     EndUpdate(gConsoleWindow);
  304.                                 end;
  305.                         end; {update}
  306.                 end; {case}
  307.  
  308.             if lastFlash + kFlashTime < TickCount then
  309.                 FlashCursor;
  310.  
  311.         until done or aborted;
  312.  
  313.         SynchCursor;
  314.  
  315.         ConsoleReadLn := ConCat(Copy(buffer[startReadY], startReadX, endRead - startReadX), Char(13));
  316.  
  317.     end; {ConsoleReadLn}
  318.  
  319.     var
  320.         readBuffer: Str255;
  321.  
  322.     function ConsoleReadChar: Char;
  323.     begin
  324.         if readBuffer = '' then
  325.             readBuffer := ConsoleReadLn;
  326.  
  327. {ConsoleReadChar := readBuffer[1];}
  328.         if readBuffer <> '' then
  329.             ConsoleReadChar := readBuffer[1]
  330.         else
  331.             ConsoleReadChar := Char(13);
  332.  
  333.         readBuffer := Copy(readBuffer, 2, Length(readBuffer) - 1);
  334.     end; {ConsoleReadChar}
  335.  
  336.     function ConsolePeekChar: Char;
  337.     begin
  338. {if readBuffer = '' then}
  339. {readBuffer := ConsoleReadLn;}
  340.  
  341.         if readBuffer <> '' then
  342.             ConsolePeekChar := readBuffer[1]
  343.         else
  344.             ConsolePeekChar := Char(13);
  345.     end; {ConsolePeekChar}
  346.  
  347.     function ConsoleReadInt: Integer;
  348.         var
  349.             theInt: Integer;
  350.             first, negative: Boolean;
  351.     begin
  352.         theInt := 0;
  353.         first := true;
  354.         negative := false;
  355.  
  356.         if readBuffer = StringOf(Char(13)) then
  357.             readBuffer := '';
  358.         if readBuffer = '' then
  359.             readBuffer := ConsoleReadLn;
  360.  
  361.         while (readBuffer <> '') do
  362.             begin
  363.                 if readBuffer = '' then
  364.                     Leave;
  365.                 if first and (readBuffer[1] = '-') then
  366.                     begin
  367.                         first := false;
  368.                         negative := true;
  369.                         readBuffer := Copy(readBuffer, 2, Length(readBuffer) - 1);
  370.                     end;
  371.                 if ((Ord(readBuffer[1]) >= Ord('0')) and (Ord(readBuffer[1]) <= Ord('9'))) then
  372.                     begin
  373.                         theInt := theInt * 10 + Ord(readBuffer[1]) - Ord('0');
  374.                         first := false;
  375.                         readBuffer := Copy(readBuffer, 2, Length(readBuffer) - 1);
  376.                     end
  377.                 else
  378.                     Leave;
  379.             end;
  380.  
  381.         if negative then
  382.             theInt := -theInt;
  383.  
  384.         ConsoleReadInt := theInt;
  385.         if readBuffer = StringOf(Char(13)) then
  386.             readBuffer := '';
  387.     end; {ConsoleReadInt}
  388.  
  389.     function ConsoleReadReal: Real;
  390.         var
  391.             theReal: Real;
  392.             i: Integer;
  393.     begin
  394.         theReal := 0.0;
  395.  
  396.         if readBuffer = StringOf(Char(13)) then
  397.             readBuffer := '';
  398.         if readBuffer = '' then
  399.             readBuffer := ConsoleReadLn;
  400.  
  401. {Skippa inledande mellanslag}
  402.         for i := 1 to Length(readBuffer) do
  403.             if readBuffer[i] <> ' ' then
  404.                 Leave;
  405. {Tag alla tecken som är tillåtna i real}
  406.         for i := i to Length(readBuffer) do
  407.             if (Ord(readBuffer[1]) < Ord('0')) and (Ord(readBuffer[1]) > Ord('9')) and (readBuffer[i] <> '.') and (readBuffer[i] <> '-') and (readBuffer[i] <> 'E') then
  408.                 Leave;
  409.  
  410.         ReadString(Copy(readBuffer, 1, i - 1), theReal);
  411.         readBuffer := Copy(readBuffer, i, Length(readBuffer) - i + 1);
  412.         ConsoleReadReal := theReal;
  413.  
  414.         if readBuffer = StringOf(Char(13)) then
  415.             readBuffer := '';
  416.  
  417.     end; {ConsoleReadReal}
  418.  
  419. {Try to mimick input^}
  420.     function ConsoleInput: CharPointer;
  421.     begin
  422.         ConsoleInput := @readBuffer[1];
  423.     end; {ConsoleInput}
  424.  
  425. {Try to mimick getfile(input)}
  426.     procedure ConsoleGet;
  427.     begin
  428.         if readBuffer = '' then
  429.             readBuffer := ConsoleReadLn
  430.         else
  431.             readBuffer := Copy(readBuffer, 2, Length(readBuffer) - 1);
  432.     end; {ConsoleGet}
  433.  
  434.     function ConsoleReadEOL: Boolean;
  435.     begin
  436.         ConsoleReadEOL := (readBuffer = '') or (readBuffer = StringOf(Char(13)));
  437.     end; {ConsoleReadEOL}
  438.  
  439.     function ConsoleReadEOF: Boolean;
  440.     begin
  441.         ConsoleReadEOF := false;
  442.     end; {ConsoleReadEOF}
  443.  
  444.     procedure ConsoleResetRead;
  445.     begin
  446.         readBuffer := '';
  447.     end; {ConsoleResetRead}
  448.  
  449.  
  450. {Hur kommer vi åt denna från P4?}
  451.     procedure ConsoleGotoXY (x, y: Integer);
  452.     begin
  453.         posX := x;
  454.         posY := y;
  455.     end; {ConsoleGotoXY}
  456.  
  457. {Denna kan vi gott styra med kontroll-koder. CHR$(12) är Form Feed.}
  458.     procedure ConsoleClearScreen;
  459.         var
  460.             i: Integer;
  461.     begin
  462.         ConsoleInit;
  463.  
  464.         for i := 0 to 23 do
  465.             buffer[i] := '                                                                                ';
  466.         posX := 1;
  467.         posY := 0;
  468.  
  469.         SetPort(gConsoleWindow);
  470.         EraseRect(gConsoleWindow^.portRect);
  471.     end; {ConsoleClearScreen}
  472.  
  473. end.